package com.hmall.search.controller;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmall.common.domain.PageDTO;
import com.hmall.search.domain.dto.ItemDTO;
import com.hmall.search.domain.po.Item;
import com.hmall.search.domain.po.ItemDoc;
import com.hmall.search.domain.query.ItemPageQuery;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.http.HttpHost;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Api(tags = "搜索相关接口")
@RestController
@RequestMapping("/search")
@RequiredArgsConstructor
public class SearchController {

    private final RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
            HttpHost.create("http://192.168.150.129:9200")
    ));

    @ApiOperation("根据ID搜索商品")
    @GetMapping("/{id}")
    public ItemDTO search(@PathVariable Long id) throws IOException {
        GetRequest request = new GetRequest("items").id(id.toString());
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        String source = response.getSourceAsString();
        ItemDoc bean = JSONUtil.toBean(source, ItemDoc.class);
        return BeanUtil.copyProperties(bean,ItemDTO.class);

    }

    @ApiOperation("搜索商品")
    @GetMapping("/list")
    public PageDTO<ItemDTO> search(ItemPageQuery query) throws IOException {
        List<ItemDTO> itemDTOList = new ArrayList<>();
        //new一个request对象
        SearchRequest request = new SearchRequest("items");
        //采用复合查询，构造复合查询的条件
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        if(query.getKey() != null && !query.getKey().isEmpty()){
            boolQueryBuilder.must( QueryBuilders.matchQuery("name",query.getKey()));
        }
        if (query.getCategory() != null && !query.getCategory().isEmpty()){
            boolQueryBuilder.filter( QueryBuilders.termQuery("category",query.getCategory()));
        }
        if (query.getBrand() != null && !query.getBrand().isEmpty()){
            boolQueryBuilder.filter( QueryBuilders.termQuery("brand",query.getBrand()));
        }
        if (query.getMaxPrice() != null){
            boolQueryBuilder.filter( QueryBuilders.rangeQuery("price").lte(query.getMaxPrice()));
        }
        if (query.getMinPrice() != null){
            boolQueryBuilder.filter( QueryBuilders.rangeQuery("price").gte(query.getMinPrice()));
        }
        //查询条件构建完成
        request.source().query(boolQueryBuilder);
        //构建排序条件
        if (query.getSortBy() != null && !query.getSortBy().isEmpty() && !query.getIsAsc()){
            request.source().sort(query.getSortBy(), SortOrder.DESC);
        } else if(query.getSortBy() != null && !query.getSortBy().isEmpty()){
            request.source().sort(query.getSortBy(), SortOrder.ASC);
        }
        //构建分页条件
        request.source().from((query.getPageNo() - 1) * 10 ).size(query.getPageSize());
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //获得总商品数
        Long total = response.getHits().getTotalHits().value;
        //计算总页数
        Long pages = total/query.getPageSize() + 1;
        //获得所有商品的数据
        SearchHit[] hits = response.getHits().getHits();
        //遍历商品数据并且进行转换
        for (SearchHit hit : hits) {
            String json = hit.getSourceAsString();
            ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);
            ItemDTO itemDTO = BeanUtil.copyProperties(itemDoc, ItemDTO.class);
            itemDTOList.add(itemDTO);
        }
        return new PageDTO<>(total,pages,itemDTOList);
    }


    @ApiOperation("过滤条件")
    @PostMapping("/filters")
    public Map<String,List<String>> filters(ItemPageQuery query) throws IOException {
        //创建request
        SearchRequest request = new SearchRequest("items");
        //准备请求参数
        if (query.getKey()!= null && !query.getKey().isEmpty()){
            request.source().query(QueryBuilders.matchQuery("name",query.getKey()));
        }
        if (query.getBrand()!=null && !query.getBrand().isEmpty()){
            request.source().query(QueryBuilders.termQuery("brand",query.getBrand()));
        }
        if (query.getCategory()!=null && !query.getCategory().isEmpty()){
            request.source().query(QueryBuilders.termQuery("category",query.getCategory()));
        }
        request.source().size(0);
        //准备聚合参数
        request.source().aggregation(
                AggregationBuilders.terms("brand_agg").field("brand").size(10)
        );
        request.source().aggregation(
                AggregationBuilders.terms("category_agg").field("category").size(10)
        );
        //发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //解析聚合结果
        Aggregations aggregations = response.getAggregations();
        Terms brandTerms = aggregations.get("brand_agg");
        Terms categoryTerms = aggregations.get("category_agg");
        List<? extends Terms.Bucket> brandTermsBuckets = brandTerms.getBuckets();
        List<? extends Terms.Bucket> categoryTermsBuckets = categoryTerms.getBuckets();

        List<String> brandList = new ArrayList<>();
        List<String> categoryList  = new ArrayList<>();
        for (Terms.Bucket bucket : brandTermsBuckets) {
            brandList.add(bucket.getKeyAsString());
        }
        for (Terms.Bucket bucket : categoryTermsBuckets) {
            categoryList.add(bucket.getKeyAsString());
        }
        Map<String,List<String>> map = new HashMap<>();
        map.put("brand",brandList);
        map.put("category",categoryList);
        return map;
    }

}
